package org.anachronos.jeep.agent;

import static org.testng.Assert.assertNotNull;

import java.io.File;
import java.util.List;

import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

import org.anachronos.jeep.agent.attach.LaunchAttachServerImpl;
import org.anachronos.jeep.agent.test.util.TestUtil;
import org.anachronos.jeep.core.agent.ProfilerRemoteControl;
import org.anachronos.jeep.core.attach.LaunchAttachServer;
import org.anachronos.jeep.core.attach.VirtualMachineAttachement;
import org.anachronos.jeep.core.attach.VirtualMachineRemoteControl;
import org.anachronos.jeep.core.trace.TraceModelBuilder;
import org.anachronos.jeep.core.trace.impl.Method;
import org.anachronos.jeep.core.trace.impl.Trace;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
import com.maschinenstuermer.example.ejb3.entity.Company;
import com.maschinenstuermer.example.ejb3.facade.ExampleFacade;
import com.maschinenstuermer.example.ejb3.facade.impl.ExampleFacadeImpl;

@Test(groups="integration")
public class JbossAppIT {
	private static final String JBOSS_SERVER_MARKER = "jboss.server";
	
	private ExampleFacade exampleFacade;

	@BeforeClass
	public void setup() throws Exception {
		final InitialContext initialContext = new InitialContext();
		final Object object = initialContext.lookup("ExampleFacadeImpl/remote");
		exampleFacade = (ExampleFacade) 
			PortableRemoteObject.narrow(object, ExampleFacade.class);
	}
	
	public void profileJbossApp() throws Exception {
		final String configFile = TestUtil.getResource(getClass(), "example-ejb3.config");

		final ProfilerRemoteControl profilerControlMBean = attachToServer(configFile);
		assertNotNull(profilerControlMBean);
		profilerControlMBean.startProfiling();
		
		Company company = new Company();
		company.setName("IBM");
		
		company = exampleFacade.makePersistent(company);
		exampleFacade.findCompaniesByName("Atari");
		exampleFacade.findCompaniesByName("IBM");
		exampleFacade.remove(company);

		profilerControlMBean.stopProfiling();
		final File tempDir = Files.createTempDir();
		final String tempTraceFile = new File(tempDir, getClass().getSimpleName() + ".trace").getAbsolutePath();
		profilerControlMBean.save(tempTraceFile);
		final Trace trace = TraceModelBuilder.load(tempTraceFile);
		
		final String internalName = getInternalName(ExampleFacadeImpl.class);
		Method method = trace.getMethod(internalName 
				+ ".makePersistent(Lcom/maschinenstuermer/example/ejb3/entity/Company;)Lcom/maschinenstuermer/example/ejb3/entity/Company;");
		assertNotNull(method);
		method = trace.getMethod(internalName 
				+ ".findCompaniesByName(Ljava/lang/String;)Ljava/util/List;");
		assertNotNull(method);
		method = trace.getMethod(internalName 
				+ ".remove(Lcom/maschinenstuermer/example/ejb3/entity/Company;)V");
		assertNotNull(method);
	}

	private String getInternalName(final Class<?> clazz) {
		return clazz.getName().replaceAll("\\.", "/");
	}
	
	private ProfilerRemoteControl attachToServer(final String configFile) throws Exception {
		final LaunchAttachServer launchAttachServer = new LaunchAttachServerImpl();
		final VirtualMachineRemoteControl virtualMachineRemoteControl = 
			launchAttachServer.launch();
		try {
			final List<VirtualMachineAttachement> allVms = virtualMachineRemoteControl.list();
			final VirtualMachineAttachement thisJvm = Iterables.find(allVms, new Predicate<VirtualMachineAttachement>() {

				@Override
				public boolean apply(VirtualMachineAttachement input) {
					return input.getSystemProperties().containsKey(JBOSS_SERVER_MARKER);
				}
			});
			return virtualMachineRemoteControl.attach(thisJvm, configFile).getProfilerRemoteControl();
		} finally {
			launchAttachServer.stop();
		}
	}
}
